using System;
using System.Collections.Generic;
using System.Text;

using System.Threading;

namespace Weazel.Microblaze.Simulator.Engine
{
    public abstract class Component
    {
        protected Thread thread;

        private AutoResetEvent clockEvent;
        public AutoResetEvent VariableUpdateEvent;

        public AutoResetEvent TickFinishedEvent;
        public AutoResetEvent VariablesUpdatedEvent;

        private SimulationContext simulator;
        public SimulationContext Context
        {
            get { return simulator; }
        }

        private List<IClockUpdateVariable> clockUpdatedVariables;

        public void Tick()
        {            
            clockEvent.Set();
        }

        protected void RegisterClockUpdatedVariable(IClockUpdateVariable variable)
        {
            this.clockUpdatedVariables.Add(variable);
        }

        public Component(SimulationContext simulator)
        {
            this.clockUpdatedVariables = new List<IClockUpdateVariable>();
            this.simulator = simulator;
            this.thread = new Thread(new ThreadStart(RunThreadBody));
            this.clockEvent = new AutoResetEvent(false);
            this.VariableUpdateEvent = new AutoResetEvent(false);
            this.VariablesUpdatedEvent = new AutoResetEvent(false);
            this.TickFinishedEvent = new AutoResetEvent(false);
            this.thread.Start();
        }

        protected void WaitClock()
        {            
            TickFinishedEvent.Set();

            VariableUpdateEvent.WaitOne();
            VariableUpdateEvent.Reset();

            foreach (IClockUpdateVariable v in clockUpdatedVariables)
                v.Update();

            VariablesUpdatedEvent.Set();

            clockEvent.WaitOne();
            clockEvent.Reset();
        }

        private void RunThreadBody()
        {             
            clockEvent.WaitOne();
            Run();            
        }

        public virtual void CleanUp()
        {
            thread.Abort();
        }

        public abstract string GetStatusString();

        public abstract void Run();        
    }
}
